#import "PowpluginPlugin.h"
#import <CoreMotion/CoreMotion.h>
#import "xlsxwriter.h"

@implementation PowpluginPlugin
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
    FlutterMethodChannel* channel = [FlutterMethodChannel
      methodChannelWithName:@"powplugin"
            binaryMessenger:[registrar messenger]];
    PowpluginPlugin* instance = [[PowpluginPlugin alloc] init];
    [registrar addMethodCallDelegate:instance channel:channel];
    
    FLTAccelerometerStreamHandler* accelerometerStreamHandler =
        [[FLTAccelerometerStreamHandler alloc] init];
    FlutterEventChannel* accelerometerChannel =
        [FlutterEventChannel eventChannelWithName:@"powplugin/sensors/accelerometer"
                                  binaryMessenger:[registrar messenger]];
    [accelerometerChannel setStreamHandler:accelerometerStreamHandler];

    FLTUserAccelStreamHandler* userAccelerometerStreamHandler =
        [[FLTUserAccelStreamHandler alloc] init];
    FlutterEventChannel* userAccelerometerChannel =
        [FlutterEventChannel eventChannelWithName:@"powplugin/sensors/user_accel"
                                  binaryMessenger:[registrar messenger]];
    [userAccelerometerChannel setStreamHandler:userAccelerometerStreamHandler];

    FLTGyroscopeStreamHandler* gyroscopeStreamHandler = [[FLTGyroscopeStreamHandler alloc] init];
    FlutterEventChannel* gyroscopeChannel =
        [FlutterEventChannel eventChannelWithName:@"powplugin/sensors/gyroscope"
                                  binaryMessenger:[registrar messenger]];
    [gyroscopeChannel setStreamHandler:gyroscopeStreamHandler];
    
    
}

static void sendTriplet(Float64 x, Float64 y, Float64 z, FlutterEventSink sink) {
  NSMutableData* event = [NSMutableData dataWithCapacity:3 * sizeof(Float64)];
  [event appendBytes:&x length:sizeof(Float64)];
  [event appendBytes:&y length:sizeof(Float64)];
  [event appendBytes:&z length:sizeof(Float64)];
  sink([FlutterStandardTypedData typedDataWithFloat64:event]);
}

- (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
  if ([@"getPlatformVersion" isEqualToString:call.method]) {
    result([@"iOS " stringByAppendingString:[[UIDevice currentDevice] systemVersion]]);
  }else if ([@"generateExcel" isEqualToString:call.method]){
      NSArray *dataArr = call.arguments;
      if (![dataArr isKindOfClass:[NSArray class]]) {
          NSLog(@"原生拿到了错误参数，返回空串");
          result(@"");
          return;
      }
      NSLog(@"原生拿到了%@条数据，处理中", @(dataArr.count));
      
      /* Create a new workbook and add a worksheet. */
      NSString *documentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES) objectAtIndex:0];

      NSString *filename = [documentPath stringByAppendingPathComponent:@"tmp.xlsx"];
      NSLog(@"创建了文件filepath:%@",filename);
      lxw_workbook  *workbook  = workbook_new(filename.UTF8String);
      lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL);
      
      for (unsigned int index=0; index<dataArr.count;index++) {
          NSDictionary *ondic = dataArr[index];
          if (![ondic isKindOfClass:[NSDictionary class]]) {
              NSLog(@"原生拿到了第%@条数据不是字典，返回空串", @(index));
              result(@"");
              return;
          }
          //写第一行title
          NSArray *titles = ondic.allKeys;
          NSArray *values = ondic.allValues;
          if (index == 0) {
              NSLog(@"写入 title");
              for (unsigned int titleIndex = 0; titleIndex < titles.count; titleIndex++) {
                  worksheet_write_string(worksheet, 0, titleIndex, [titles[titleIndex] UTF8String], NULL);
              }
          }
          
          NSLog(@"写入数据");
          //存数据
          for (unsigned int titleIndex = 0; titleIndex < titles.count; titleIndex++) {
              worksheet_write_string(worksheet,  1+index, titleIndex, [[values[titleIndex] description] UTF8String], NULL);
              worksheet_write_string(worksheet, 1+index,titleIndex,  [[values[titleIndex] description] UTF8String], NULL);
          }
          
      }
      workbook_close(workbook);
      result(filename);
  } else {
    result(FlutterMethodNotImplemented);
  }
}

@end


const double GRAVITY = 9.8;
CMMotionManager* _motionManager;

void _initMotionManager() {
  if (!_motionManager) {
    _motionManager = [[CMMotionManager alloc] init];
  }
}

@implementation FLTAccelerometerStreamHandler

- (FlutterError*)onListenWithArguments:(id)arguments eventSink:(FlutterEventSink)eventSink {
  _initMotionManager();
  _motionManager.accelerometerUpdateInterval = (float)1 / [arguments integerValue];
  [_motionManager
      startAccelerometerUpdatesToQueue:[[NSOperationQueue alloc] init]
                           withHandler:^(CMAccelerometerData* accelerometerData, NSError* error) {
                             CMAcceleration acceleration = accelerometerData.acceleration;
                             // Multiply by gravity, and adjust sign values to
                             // align with Android.
                             sendTriplet(-acceleration.x * GRAVITY, -acceleration.y * GRAVITY,
                                         -acceleration.z * GRAVITY, eventSink);
                           }];
  return nil;
}

- (FlutterError*)onCancelWithArguments:(id)arguments {
  [_motionManager stopAccelerometerUpdates];
  return nil;
}

@end

@implementation FLTUserAccelStreamHandler

- (FlutterError*)onListenWithArguments:(id)arguments eventSink:(FlutterEventSink)eventSink {
    _initMotionManager();
    _motionManager.deviceMotionUpdateInterval = (float)1 / [arguments integerValue];
    [_motionManager
      startDeviceMotionUpdatesToQueue:[[NSOperationQueue alloc] init]
                          withHandler:^(CMDeviceMotion* data, NSError* error) {
                            CMAcceleration acceleration = data.userAcceleration;
                            // Multiply by gravity, and adjust sign values to align with Android.
                            sendTriplet(-acceleration.x * GRAVITY, -acceleration.y * GRAVITY,
                                        -acceleration.z * GRAVITY, eventSink);
                          }];
  return nil;
}

- (FlutterError*)onCancelWithArguments:(id)arguments {
  [_motionManager stopDeviceMotionUpdates];
  return nil;
}

@end

@implementation FLTGyroscopeStreamHandler

- (FlutterError*)onListenWithArguments:(id)arguments eventSink:(FlutterEventSink)eventSink {
  _initMotionManager();
  _motionManager.gyroUpdateInterval = (float)1 / [arguments integerValue];
  [_motionManager
      startGyroUpdatesToQueue:[[NSOperationQueue alloc] init]
                  withHandler:^(CMGyroData* gyroData, NSError* error) {
                    CMRotationRate rotationRate = gyroData.rotationRate;
                    sendTriplet(rotationRate.x, rotationRate.y, rotationRate.z, eventSink);
                  }];
  return nil;
}

- (FlutterError*)onCancelWithArguments:(id)arguments {
  [_motionManager stopGyroUpdates];
  return nil;
}

@end
